/**
 *   FUSE-J: Java bindings for FUSE (Filesystem in Userspace by Miklos Szeredi (mszeredi@inf.bme.hu))
 *
 *   Copyright (C) 2003 Peter Levart (peter@select-tech.si)
 *
 *   This program can be distributed under the terms of the GNU LGPL.
 *   See the file COPYING.LIB
 */

package fuse;

import fuse.util.Log;

import java.io.File;
import java.nio.ByteBuffer;


public class FakeFilesystem implements Filesystem
{
   private static final Log log = new Log(FakeFilesystem.class);


   public FakeFilesystem()
   {
      log.info("created");
   }


   public void chmod(String path, int mode) throws FuseException
   {
      log.info(path + " " + mode);
   }

   public void chown(String path, int uid, int gid) throws FuseException
   {
      log.info(path + " " + uid + " " + gid);
   }

   public FuseStat getattr(String path) throws FuseException
   {
      log.info(path);

      String normPath = new File(path).toURI().normalize().getPath();

      if (normPath.equals("/"))
      {
         FuseStat stat = new FuseStat();

         stat.mode = FuseFtype.TYPE_DIR | 0755;
         stat.nlink = 1;
         stat.uid = 0;
         stat.gid = 0;
         stat.size = 123;
         stat.atime = stat.mtime = stat.ctime = (int)(System.currentTimeMillis() / 1000L);
         stat.blocks = 1;

         return stat;
      }
      else
      {
         File file = new File(normPath);
         if (file.getParent().equals("/"))
         {
            FuseStat stat = new FuseStat();

            stat.mode = FuseFtype.TYPE_SYMLINK | 0666;
            stat.nlink = 1;
            stat.uid = 0;
            stat.gid = 0;
            stat.size = 123;
            stat.atime = stat.mtime = stat.ctime = (int)(System.currentTimeMillis() / 1000L);
            stat.blocks = 1;

            return stat;
         }
         else
            throw new FuseException("No such file: " + file).initErrno(FuseException.ENOENT);
      }
   }

   public FuseDirEnt[] getdir(String path) throws FuseException
   {
      log.info(path);

      String normPath = new File(path).toURI().normalize().getPath();

      if (normPath.equals("/"))
      {
         FuseDirEnt[] dirEnts = new FuseDirEnt[3];

         for (int i = 0; i < dirEnts.length; i++)
         {
            FuseDirEnt dirEnt = new FuseDirEnt();
            dirEnts[i] = dirEnt;

            dirEnt.mode = FuseFtype.TYPE_SYMLINK | 0666;
            dirEnt.name = "symlink" + i;
         }

         return dirEnts;
      }
      else
         throw new FuseException("Not a directory: " + path).initErrno(FuseException.ENOTDIR);
   }

   public void link(String from, String to) throws FuseException
   {
      log.info(from + " " + to);
   }

   public void mkdir(String path, int mode) throws FuseException
   {
      log.info(path + " " + mode);
   }

   public void mknod(String path, int mode, int rdev) throws FuseException
   {
      log.info(path + " " + mode + " " + rdev);
   }

   public long open(String path, int flags) throws FuseException
   {
      log.info(path + " " + flags);

      return (long) path.hashCode();
   }

   public void rename(String from, String to) throws FuseException
   {
      log.info(from + " " + to);
   }

   public void rmdir(String path) throws FuseException
   {
      log.info(path);
   }

   public FuseStatfs statfs() throws FuseException
   {
      log.info("called");

      FuseStatfs statfs = new FuseStatfs();

      statfs.blocks = 100;
      statfs.blocksFree = 97;
      statfs.files = 50;
      statfs.filesFree = 47;
      statfs.blockSize = 512;
      statfs.namelen = 1024;

      return statfs;
   }

   public void symlink(String from, String to) throws FuseException
   {
      log.info(from + " " + to);
   }

   public void truncate(String path, long size) throws FuseException
   {
      log.info(path + " " + size);
   }

   public void unlink(String path) throws FuseException
   {
      log.info(path);
   }

   public void utime(String path, int atime, int mtime) throws FuseException
   {
      log.info(path + " " + atime + " " + mtime);
   }

   public String readlink(String path) throws FuseException
   {
      log.info(path);

      return "/etc/hosts";
   }

   // CHANGE-22: fh is filehandle passed from open,
   //            isWritepage indicates that write was caused by a writepage
   public void write(String path, long fh, boolean isWritepage, ByteBuffer buf, long offset) throws FuseException
   {
      log.info(path + " " + offset);
   }

   // CHANGE-22: fh is filehandle passed from open
   public void read(String path, long fh, ByteBuffer buf, long offset) throws FuseException
   {
      log.info(path + " " + offset);
   }

   // CHANGE-22: new operation (called on every filehandle close), fh is filehandle passed from open
   public void flush(String path, long fh) throws FuseException
   {
      log.info(path);
   }

   // CHANGE-22: (called when last filehandle is closed), fh is filehandle passed from open
   public void release(String path, long fh, int flags) throws FuseException
   {
      log.info(path + " " + flags);
   }

   // CHANGE-22: new operation (Synchronize file contents), fh is filehandle passed from open,
   //            isDatasync indicates that only the user data should be flushed, not the meta data
   public void fsync(String path, long fh, boolean isDatasync) throws FuseException
   {
      log.info(path);
   }

   //
   // Java entry point

   public static void main(String[] args)
   {
      log.info("entering");

      try
      {
         FuseMount.mount(args, new FakeFilesystem());
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }
      finally
      {
         log.info("exiting");
      }
   }
}
